package com.net.xpay.common.service.impl;

import com.google.common.base.Preconditions;
import com.net.xpay.common.domain.DailyTaskRecord;
import com.net.xpay.common.domain.stat.CompanyDailyStat;
import com.net.xpay.common.manager.UserManager;
import com.net.xpay.common.manager.stat.CompanyDailyStatManager;
import com.net.xpay.common.manager.sync.CommonPayTransBatchManager;
import com.net.xpay.common.manager.sync.CommonSafePayBatchManager;
import com.net.xpay.common.service.CompanyDailyStatService;
import com.net.xpay.core.enums.SafePayOrderStatus;
import com.net.xpay.core.manager.ChargeRecordManager;
import com.net.xpay.core.manager.PayTransBatchManager;
import com.net.xpay.core.manager.PayTransManager;
import com.net.xpay.core.manager.safePay.SafePayBatchManager;
import com.net.xpay.core.manager.safePay.SafePayOrderManager;
import com.net.xpay.core.model.*;
import com.net.common.util.LocalDateUtil;
import com.net.xpay.core.model.*;
import com.net.shard.ShardDataSource;
import com.net.shard.ShardDataSourceConfigurer;
import com.net.shard.ShardUtil;
import com.net.shard.domain.ShardConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Map;

@Service
@Slf4j
public class CompanyDailyStatServiceImpl implements CompanyDailyStatService {

    @Autowired
    private UserManager userManager;

    @Autowired
    private PayTransBatchManager payTransBatchManager;

    @Autowired
    private SafePayBatchManager safePayBatchManager;

    @Autowired
    private CommonPayTransBatchManager commonPayTransBatchManager;

    @Autowired
    private CommonSafePayBatchManager commonSafePayBatchManager;

    @Autowired
    private ChargeRecordManager chargeRecordManager;

    @Autowired
    private PayTransManager payTransManager;

    @Autowired
    private SafePayOrderManager safePayOrderManager;

    @Autowired
    private CompanyDailyStatManager companyDailyStatManager;

    @Autowired
    @Qualifier("shardDataSource")
    private DataSource shardDataSource;


    @Override
    public void statCompanyDailyStat(LocalDate day, DailyTaskRecord record) {
        ShardDataSourceConfigurer shardDataSourceConfigurer = ((ShardDataSource) shardDataSource).getShardDataSourceConfigurer();
        Map<Long, ShardConfig> shardConfigMap = shardDataSourceConfigurer.getShardConfigMap();
        Preconditions.checkArgument(CollectionUtils.isNotEmpty(shardConfigMap.keySet()));
        CompanyDailyStat stat = CompanyDailyStat.getInstance();
        // 获取当天的起始时间和终止时间 终止时间保留在23:59:59.999999999
        LocalDateTime minEndTime = LocalDateUtil.getDayStart(day);
        LocalDateTime maxEndTime = LocalDateUtil.getDayEnd(day);
        //新增商户数
        long registerCount = userManager.countUserRegister(minEndTime, maxEndTime);
        stat.setRegisterCount(registerCount);
        //批量有密活跃渠道数
        long payTransActivePartnerCount = commonPayTransBatchManager.statPayTransActivePartnerCount(minEndTime,maxEndTime);
        //安全发活跃渠道数
        long safePayActivePartnerCount = commonSafePayBatchManager.statSafePayActivePartnerCount(minEndTime,maxEndTime);
        //活跃渠道数
        stat.setPayTransActivePartnerCount(payTransActivePartnerCount);
        stat.setSafePayActivePartnerCount(safePayActivePartnerCount);
        //分库
        for (Long shardId : shardConfigMap.keySet()) {
            try {
                ShardUtil.setShardContext(shardId);
                log.info("statDailyCompanyBill start in shard={}|day={}", shardId, day);

                // 先去判断当天统计记录是否存在
                stat.setDay(day);
                boolean exitRecord = hasStated(stat);
                if (exitRecord) {
                    log.warn("doCompanyDailyStat the record |day={} is already exist", day);
                    return;
                }
                //统计数据
                saveCompanyDailyStat(minEndTime, maxEndTime, stat);

                log.info("statDailyCompanyBill end in shard={}|day={}", shardId, day);
            } finally {
                ShardUtil.cleanShardContext();
            }
        }
        companyDailyStatManager.save(stat);
    }

    @Override
    public CompanyDailyStat statCompanyDailyStatByTime(LocalDateTime minEndTime, LocalDateTime maxEndTime) {
        ShardDataSourceConfigurer shardDataSourceConfigurer = ((ShardDataSource) shardDataSource).getShardDataSourceConfigurer();
        Map<Long, ShardConfig> shardConfigMap = shardDataSourceConfigurer.getShardConfigMap();
        Preconditions.checkArgument(CollectionUtils.isNotEmpty(shardConfigMap.keySet()));
        //初始化
        CompanyDailyStat stat = CompanyDailyStat.getInstance();

        //新增商户数
        long registerCount = userManager.countUserRegister(minEndTime, maxEndTime);
        stat.setRegisterCount(registerCount);
        //批量有密活跃渠道数
        long payTransActivePartnerCount = commonPayTransBatchManager.statPayTransActivePartnerCount(minEndTime,maxEndTime);
        //安全发活跃渠道数
        long safePayActivePartnerCount = commonSafePayBatchManager.statSafePayActivePartnerCount(minEndTime,maxEndTime);
        //活跃渠道数
        stat.setPayTransActivePartnerCount(payTransActivePartnerCount);
        stat.setSafePayActivePartnerCount(safePayActivePartnerCount);
        //分库
        for (Long shardId : shardConfigMap.keySet()) {
            try {
                ShardUtil.setShardContext(shardId);
                //统计数据
                saveCompanyDailyStat(minEndTime, maxEndTime, stat);
            } finally {
                ShardUtil.cleanShardContext();
            }
        }

        return stat;
    }


    private void saveCompanyDailyStat(LocalDateTime minEndTime, LocalDateTime maxEndTime, CompanyDailyStat stat) {
        //统计查询
        //批量有密活跃用户 or 付款支付宝账户数
        PayTransDailyStatModel payTransDailyStatModel = payTransBatchManager.statActivePartnerCount(minEndTime, maxEndTime);
        //安全发活跃 用户 or 付款支付宝账户数
        SafePayTransDailyStatModel safePayTransDailyStatModel = safePayBatchManager.statActivePartnerCount(minEndTime, maxEndTime);

        //收款支付宝
        long payTransPayeeAlipayAccount = payTransManager.statPayTransPayeeAlipayAccount(minEndTime, maxEndTime);
        long safePayTransPayeeAlipayAccount = safePayOrderManager.statSafePayTransPayeeAlipayAccount(minEndTime, maxEndTime);
        //服务费充值金额
        long serviceChargeFee = chargeRecordManager.sumCompanyServiceChargeFeeByDay(minEndTime, maxEndTime);
        //批量有密单笔超过500金额成功笔数
        long payTransSuccessSingleVeryCount = payTransManager.statSingleVeryCount(minEndTime, maxEndTime);
        //批量有密单笔超过500金额失败笔数
        long payTransFailSingleVeryCount = payTransManager.statFailSingleVeryCount(minEndTime, maxEndTime);
        //安全发到卡转账金额
        SafePayTransBankDailyStatModel safePayTransBankDailyStatModel = safePayBatchManager.statSafePayTransBankAmount(minEndTime, maxEndTime);
        //安全发单笔超过500金额成功笔数
        long safePayTransSuccessSingleVeryCount = safePayOrderManager.statSingleVeryCount(minEndTime, maxEndTime, SafePayOrderStatus.SUCCESS);
        //安全发单笔超过500金额失败笔数
        long safePayTransFailSingleVeryCount = safePayOrderManager.statSingleVeryCount(minEndTime, maxEndTime, SafePayOrderStatus.FAIL);
        //安全发超过500万账户数
        long safePayTransVeryAlipayUserCount = safePayBatchManager.sumTotalVeryAlipayUserCount(minEndTime, maxEndTime);
        //批量有密超过500万账户数
        long payTransVeryAlipayUserCount = payTransBatchManager.sumTotalVeryAlipayUserCount(minEndTime, maxEndTime);

        //payTransBatch表统计
        CompanyPayTransDayStatModel companyPayTransDayStatModel = payTransBatchManager.sumCompanyPayTransDay(minEndTime, maxEndTime);
        //safePayTransBatch表统计
        CompanySafePayTransDayStatModel companySafePayTransDayStatModel = safePayBatchManager.sumCompanySafePayTransDay(minEndTime, maxEndTime);

        //设值
        BigDecimal finalServiceChargeFee = new BigDecimal(serviceChargeFee).multiply(new BigDecimal("0.01")).setScale(2, RoundingMode.HALF_UP);
        stat.setServiceChargeFee(stat.getServiceChargeFee().add(finalServiceChargeFee));
        //服务费支出
        stat.setPayTransServicePrice(stat.getPayTransServicePrice().add(new BigDecimal(companyPayTransDayStatModel.getPayTransServicePrice()).multiply(new BigDecimal("0.01")).setScale(2, RoundingMode.HALF_UP)));
        stat.setSafePayTransServicePrice(stat.getSafePayTransServicePrice().add(new BigDecimal(companySafePayTransDayStatModel.getSafePayTransServicePrice()).multiply(new BigDecimal("0.01")).setScale(2, RoundingMode.HALF_UP)));
        stat.setTotalServicePrice(stat.getPayTransServicePrice().add(stat.getSafePayTransServicePrice()));
        //转账笔数
        stat.setSafePayTransCount(stat.getSafePayTransCount() + companySafePayTransDayStatModel.getSafePayTransCount());
        stat.setPayTransCount(stat.getPayTransCount() + companyPayTransDayStatModel.getPayTransCount());
        stat.setTotalCount(stat.getPayTransCount() + stat.getSafePayTransCount());
        //总金额
        stat.setPayTransAmount(stat.getPayTransAmount().add(companyPayTransDayStatModel.getPayTransAmount()));
        stat.setSafePayTransAmount(stat.getSafePayTransAmount().add(companySafePayTransDayStatModel.getSafePayTransAmount()));
        stat.setTotalTransAmount(stat.getPayTransAmount().add(stat.getSafePayTransAmount()));
        //成功金额
        stat.setPayTransSuccessAmount(stat.getPayTransSuccessAmount().add(companyPayTransDayStatModel.getPayTransSuccessAmount()));
        stat.setSafePayTransSuccessAmount(stat.getSafePayTransSuccessAmount().add(companySafePayTransDayStatModel.getSafePayTransSuccessAmount()));
        stat.setTotalSuccessTransAmount(stat.getPayTransSuccessAmount().add(stat.getSafePayTransSuccessAmount()));
        //成功笔数
        stat.setPayTransSuccessCount(stat.getPayTransSuccessCount() + companyPayTransDayStatModel.getPayTransSuccessCount());
        stat.setSafePayTransSuccessCount(stat.getSafePayTransSuccessCount() + companySafePayTransDayStatModel.getSafePayTransSuccessCount());
        stat.setTotalSuccessCount(stat.getPayTransSuccessCount() + stat.getSafePayTransSuccessCount());
        //失败金额
        stat.setPayTransFailAmount(stat.getPayTransFailAmount().add(companyPayTransDayStatModel.getPayTransFailAmount()));
        stat.setSafePayTransFailAmount(stat.getSafePayTransFailAmount().add(companySafePayTransDayStatModel.getSafePayTransFailAmount()));
        stat.setTotalFailTransAmount(stat.getPayTransFailAmount().add(stat.getSafePayTransFailAmount()));
        //失败笔数
        stat.setPayTransFailCount(stat.getPayTransFailCount() + companyPayTransDayStatModel.getPayTransFailCount());
        stat.setSafePayTransFailCount(stat.getSafePayTransFailCount() + companySafePayTransDayStatModel.getSafePayTransFailCount());
        stat.setTotalFailCount(stat.getPayTransFailCount() + stat.getSafePayTransFailCount());
        //批量有密单笔超过500金额成功笔数
        stat.setPayTransSuccessSingleVeryCount(stat.getPayTransSuccessSingleVeryCount() + payTransSuccessSingleVeryCount);
        //批量有密单笔超过500金额失败笔数
        stat.setPayTransFailSingleVeryCount(stat.getPayTransFailSingleVeryCount() + payTransFailSingleVeryCount);
        //批量有密超过500万账户数
        stat.setPayTransVeryAlipayUserCount(stat.getPayTransVeryAlipayUserCount() + payTransVeryAlipayUserCount);
        //安全发单笔超过500金额成功笔数
        stat.setSafePayTransSuccessSingleVeryCount(stat.getSafePayTransSuccessSingleVeryCount() + safePayTransSuccessSingleVeryCount);
        //安全发单笔超过500金额失败笔数
        stat.setSafePayTransFailSingleVeryCount(stat.getSafePayTransFailSingleVeryCount() + safePayTransFailSingleVeryCount);
        //安全发超过500万账户数
        stat.setSafePayTransVeryAlipayUserCount(stat.getSafePayTransVeryAlipayUserCount() + safePayTransVeryAlipayUserCount);
        //活跃用户数
        stat.setPayTransActiveUserCount(stat.getPayTransActiveUserCount() + payTransDailyStatModel.getPayTransActiveUserCount());
        stat.setSafePayActiveUserCount(stat.getSafePayActiveUserCount() + safePayTransDailyStatModel.getSafePayActiveUserCount());

        //付款支付宝账户数
        stat.setPayTransPayerAlipayAccountCount(stat.getPayTransPayerAlipayAccountCount() + payTransDailyStatModel.getPayTransPayerAlipayAccountCount());
        stat.setSafePayPayerAlipayAccountCount(stat.getSafePayPayerAlipayAccountCount() + safePayTransDailyStatModel.getSafePayPayerAlipayAccountCount());
        //收款支付宝账户数
        stat.setPayTransPayeeAlipayAccountCount(stat.getPayTransPayeeAlipayAccountCount() + payTransPayeeAlipayAccount);
        stat.setSafePayPayeeAlipayAccountCount(stat.getSafePayPayeeAlipayAccountCount() + safePayTransPayeeAlipayAccount);
        //单笔超过500金额总成功笔数
        stat.setTotalSuccessSingleVeryCount(stat.getPayTransSuccessSingleVeryCount() + stat.getSafePayTransSuccessSingleVeryCount());
        //单笔超过500金额总失败笔数
        stat.setTotalFailSingleVeryCount(stat.getPayTransFailSingleVeryCount() + stat.getSafePayTransFailSingleVeryCount());
        //平台总收益
        stat.setTotalSafePayTransBenefit(stat.getTotalSafePayTransBenefit().add(new BigDecimal(companySafePayTransDayStatModel.getTotalSafePayTransBenefit()).multiply(new BigDecimal("0.01")).setScale(2, RoundingMode.HALF_UP)));
        stat.setTotalPayTransBenefit(stat.getTotalPayTransBenefit().add(new BigDecimal(companyPayTransDayStatModel.getTotalPayTransBenefit()).multiply(new BigDecimal("0.01")).setScale(2, RoundingMode.HALF_UP)));
        stat.setTotalBenefit(stat.getTotalPayTransBenefit().add(stat.getTotalSafePayTransBenefit()));

        //安全发到卡总金额 & 成功金额
        stat.setSafePayTransBankAmount(stat.getSafePayTransBankAmount().add(safePayTransBankDailyStatModel.getSafePayTransBankAmount()));
        stat.setSafePayTransSuccessBankAmount(stat.getSafePayTransSuccessBankAmount().add(safePayTransBankDailyStatModel.getSafePayTransSuccessBankAmount()));
        //安全发到支付宝总金额 & 成功金额
        stat.setSafePayTransAlipayAmount(stat.getSafePayTransAmount().subtract(stat.getSafePayTransBankAmount()));
        stat.setSafePayTransSuccessAlipayAmount(stat.getSafePayTransSuccessAmount().subtract(stat.getSafePayTransSuccessBankAmount()));
        //到卡总金额 & 总成功金额 只有安全发
        stat.setTotalTransBankAmount(stat.getTotalTransBankAmount().add(stat.getSafePayTransBankAmount()));
        stat.setTotalSuccessTransBankAmount(stat.getTotalSuccessTransBankAmount().add(stat.getSafePayTransSuccessBankAmount()));
        //到支付宝总金额 & 总成功金额
        stat.setTotalTransAlipayAmount(stat.getSafePayTransAlipayAmount().add(stat.getPayTransAmount()));
        stat.setTotalSuccessTransAlipayAmount(stat.getPayTransSuccessAmount().add(stat.getSafePayTransAlipayAmount()));
    }


    private boolean hasStated(CompanyDailyStat stat) {
        LocalDate day = stat.getDay();
        // 尝试通过时间加id获取数据
        CompanyDailyStat companyDailyStatRecord = companyDailyStatManager.findByDay(day);
        // 若果查到了数据，表示不需要在插入记录了
        return companyDailyStatRecord != null;
    }
}
